package springs;

import forces.Force;
import masses.Mass;
import java.awt.*;
import java.awt.geom.Point2D;


/**
 * Author: Zach Michaelov
 * Date: 9/22/12
 * Time: 3:30 AM
 */
public abstract class AbstractSpring {
    private Mass myStart;
    private Mass myEnd;
    private double myLength;
    private double myK;

    public AbstractSpring (Mass start, Mass end, double length, double kVal) {
        myLength = length;
        myEnd = end;
        myK = kVal;
        myStart = start;
    }

    /**
     * Updates the Spring's state based on its properties
     * and external forces acting on it
     * 
     * @param dt time elapsed since last subsequent update
     */
    public void update (double dt) {

        Point2D start = this.getMyStart().getCenter();
        Point2D end = this.getMyEnd().getCenter();
        double dx = start.getX() - end.getX();
        double dy = start.getY() - end.getY();

        // apply a driving force to the spring, if there is one
        this.applyDrivingForce(dt);
        // apply hooke's law to each attached mass
        Force f = new Force(Force.angleBetween(dx, dy), this.getMyK()
                * (this.getMyLength() - Force.distanceBetween(dx, dy)));

        this.getMyStart().applyForce(f);
        f.negate();
        this.getMyEnd().applyForce(f);
    }

    /**
     * repaint the Spring on the Canvas based on its updated state
     * 
     * @param pen the Graphics2D object used for painting
     */
    public void paint (Graphics2D pen) {
        int xStart = (int) myStart.getCenter().getX();
        int yStart = (int) myStart.getCenter().getY();
        int xEnd = (int) myEnd.getCenter().getX();
        int yEnd = (int) myEnd.getCenter().getY();
        double dx = xStart - xEnd;
        double dy = yStart - yEnd;
        double len = Math.sqrt(dx * dx + dy * dy) - myLength;

        if (Math.abs(len) < 0.001) {
            pen.setColor(Color.WHITE);
        }
        else if (len < 0.0) {
            pen.setColor(Color.BLUE);
        }
        else {
            pen.setColor(Color.RED);
        }
        pen.drawLine(xStart, yStart, xEnd, yEnd);
    }

    // modification: added accessor methods

    public Mass getMyStart () {
        return myStart;
    }

    public Mass getMyEnd () {
        return myEnd;
    }

    public double getMyLength () {
        return myLength;
    }

    public void setMyLength (double myLength) {
        this.myLength = myLength;
    }

    public double getMyK () {
        return myK;
    }

    /**
     * Applies a driving Force to the Spring, if there is one.
     * Such as in the case of Muscle.
     * 
     * @param dt change in time used the calculate magnitude of driving Force
     */
    public abstract void applyDrivingForce (double dt);
}
